#include "mainwindow.h"
#include <QAbstractSocket>
#include <QCheckBox>
#include <QDateTime>
#include <QFileDialog>
#include <QPushButton>
#include <QSettings>
#include <QStandardPaths>
#include <QStringListModel>
#include <QStyledItemDelegate>
#include <QTcpSocket>
#include <QTextEdit>
#include <QThread>
#include <QVBoxLayout>
#include <Qstring>
#include <qmessagebox>
#include <QApplication>
#include <QPixmap>
#include <QPalette>
#include <QBrush>


// #include "operatefile.h"
#include "ui_mainwindow.h"

// static int BUF_SIZE = 1024;

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent), ui(new Ui::MainWindow) {
    ui->setupUi(this);
    setWindowTitle("TCP客户端");

    //back
    QPixmap pixmap("./back");
    // 根据控件的大小缩放图片，不保持宽高比
    pixmap = pixmap.scaled(this->size(), Qt::KeepAspectRatioByExpanding, Qt::SmoothTransformation);
    //pixmap = pixmap.scaled(this->size(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
    QBrush brush(pixmap);
    QPalette palette;
    palette.setBrush(QPalette::Window, brush);
    this->setPalette(palette);
    this->setAutoFillBackground(true);


    socket = new QTcpSocket(this);
    // 只读模式
    ui->TEmessage->setReadOnly(true);

    // 设置样式表
    ui->progressBar->setStyleSheet("QProgressBar {"
                                   "    border: 1px solid gray;"
                                   "    border-radius: 5px;"
                                   "    background-color: white;"
                                   "}"
                                   "QProgressBar::chunk {"
                                   "    background-color: green;"
                                   "    width: 20px;"
                                   "}");
    // 原文链接：https://blog.csdn.net/qq_37529913/article/details/132819238

    ui->progressBar->setRange(0, 100);
    ui->progressBar->setValue(0);

    // 多线程
    {
    // //
    // 控件不可通过键盘修改内容，但仍响应鼠标事件，可通过鼠标按键和滚轮完成数据调整；
    // ui->TEmessage->setFocusPolicy(Qt::NoFocus);
    // // 此属性限制了键盘和鼠标事件，因此当设置enabled=false时，控件不可编辑；
    // ui->spinBox->setEnabled(false);

    // // 创建线程对象
    // QThread* thr = new QThread;
    // //
    // OperateFile* worker = new OperateFile;
    // // 让worker对象在子线程中执行
    // worker->moveToThread(thr);

    // // 连接服务器
    // connect(this, &MainWindow::startConnect, worker,
    // &OperateFile::connectServer); // 让子线程连接服务器 connect(worker,
    // &OperateFile::connectOK, this,[=]{
    //     // 获取当前时间并格式化为字符串
    //     QDateTime currentDateTime = QDateTime::currentDateTime();
    //     QString timeString = currentDateTime.toString("yyyy-MM-dd HH:mm:ss
    //     ");

    //     // 准备要输出的消息，包括时间戳
    //     QString message = timeString + "连接服务器成功";
    //     ui->TEmessage->append(message);
    // });
    // connect(worker, &OperateFile::connectOK, this,[=]{
    //     // 获取当前时间并格式化为字符串
    //     QDateTime currentDateTime = QDateTime::currentDateTime();
    //     QString timeString = currentDateTime.toString("yyyy-MM-dd HH:mm:ss
    //     ");

    //     // 准备要输出的消息，包括时间戳
    //     QString message = timeString + "连接服务器失败，请重新连接。";
    //     ui->TEmessage->append(message);
    //     // 资源释放
    //     thr->quit();
    //     thr->wait();
    //     worker->deleteLater();
    //     thr->deleteLater();
    // });

    // // 发送文件
    // connect(this, &MainWindow::sendFile, worker, &OperateFile::sendFile); //
    // 让子线程发送文件 connect(worker, &OperateFile::curPercent,
    // ui->progressBar, &QProgressBar::setValue); // 让进度条变化

    // // 启动子线程
    // thr->start();
    }
    // qDebug() << "check_socket called";

    connect(socket, &QTcpSocket::readyRead, this, &MainWindow::onReadyRead);

    check_socket(); // 自动连接
}

MainWindow::~MainWindow() { delete ui; }

void MainWindow::setUsername(QString user) { username = user; }

// 检查登录,连接
void MainWindow::check_socket() {

    // unsigned short port = 8936;
    // QString ip = "111.231.80.52";

    // emit startConnect(ip, port);

    // 创建QTcpSocket对象用于网络通信
    socket->connectToHost(QHostAddress("111.231.80.52"), 8936);

    // 等待连接操作完成，设置超时时间,5秒超时
    if (!socket->waitForConnected(5000)) {
        qDebug() << "Connection failed:" << socket->errorString();
        ui->TEmessage->append("连接服务器失败，请重新连接。");
        ui->widget_7->setEnabled(false);
        socket->abort();
        return;
    }

    // 如果连接成功，输出信息
    // 获取当前时间并格式化为字符串
    QDateTime currentDateTime = QDateTime::currentDateTime();
    QString timeString = currentDateTime.toString("yyyy-MM-dd HH:mm:ss ");

    // 准备要输出的消息，包括时间戳
    // qDebug() << "check_socket called";
    QString message = timeString + "连接服务器成功";
    ui->TEmessage->append(message);

    on_newRe_clicked();

    // on_btnReload_clicked();
    // QMetaObject::invokeMethod(this, "on_btnReload_clicked",
    // Qt::QueuedConnection);
    return;
}

// 用户点击
void MainWindow::on_btnUser_clicked() {
    // 检查socket状态
    // check_socket();
    if (socket->state() == QAbstractSocket::UnconnectedState) {
        // 只有登录成功才能跳转到此
        check_socket();
        qDebug() << "[function on_btnUser_clicked]: connect error!Please connect.";
        qDebug() << "[function on_btnUser_clicked]: close thiswindows";
        // this->close();
        return;
    } else if (socket->state() == QAbstractSocket::ConnectedState) {
        // 如果已经连接，直接发送数据
        // qDebug() << "[function on_btnUser_clicked]:Socket already connected. "
        //             "Sending data. on_btnUser_clicked";
        // 如果连接成功，输出信息
        // 获取当前时间并格式化为字符串
        QDateTime currentDateTime = QDateTime::currentDateTime();
        QString timeString = currentDateTime.toString("yyyy-MM-dd HH:mm:ss ");

        // 准备要输出的消息，包括时间戳
        // qDebug() << "check_socket called";
        QString message = timeString + "服务器已连接";
        ui->TEmessage->append(message);
    } else {
        qDebug() << "[function on_btnUser_clicked]:Socket is in a state not ready "
                    "for connection. Current state:"
                 << socket->state();
        return; // 早期返回，不进行任何操作
    }
}

// 选择要上传的文件
void MainWindow::on_btnUpload_clicked() { open(); }

// 打开文件夹选择文件
void MainWindow::open() {
    // 配置setting.ini的路径
    QString config_path = qApp->applicationDirPath() + "/setting.ini";
    // 检查配置文件文件是否存在，如果不存在则创建
    QFile configFile(config_path);
    if (!configFile.exists()) {
        // 创建文件
        if (!configFile.open(QIODevice::WriteOnly | QIODevice::Text)) {
            // 使用QTextStream来写入文本
            QTextStream out(&configFile);
            // 写入配置内容
            out << "[OpenPath]\npath=\n";
            // 关闭文件
            configFile.close();
        }
    }

    // 智能指针,如果没有设置路径则重新设置默认路径
    std::unique_ptr<QSettings> pIniSet(
        new QSettings(config_path, QSettings::IniFormat));
    QString open_path = pIniSet->value("/OpenPath/path").toString();
    if (open_path.isEmpty()) { // 判断路径是否为空
        open_path =
            QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
        /***
     * DesktopLocation：桌面目录。
     * DocumentsLocation：文档目录。
     * FontsLocation：字体目录。
     * ApplicationsLocation：应用程序目录。
     * MusicLocation：音乐目录。
     * MoviesLocation：电影目录。
     * PicturesLocation：图片目录。
     * TempLocation：临时目录。
     **/
        // QCoreApplication::applicationDirPath();
    }

    // 文件选择界面
    QString fileName = QFileDialog::getOpenFileName(
        this, "请选择图片", open_path, "所有文件(*);;图片(*.png *.jpg);;");
    // if (fileName.isEmpty()) {
    //     QMessageBox::warning(this, "打开文件", "选择的文件路径不能为空！");
    //     return;
    // }

    // 显示文件名称
    ui->lineEdit_file->setText(fileName);
    uploadFileName = fileName; // 保存当前上传文件的路径

    // 保存这次文件夹路径
    int end = fileName.lastIndexOf("/");
    QString lastpath = fileName.left(end);
    pIniSet->setValue("/OpenPath/path", lastpath);
}

// 确认上传文件
void MainWindow::on_btnOk_clicked() {
    if (ui->lineEdit_file->text().isEmpty()) {
        QMessageBox::warning(this, "打开文件", "选择的文件路径不能为空！");
        return;
    }
    // 将文件名去除路径
    QString filename = uploadFileName;
    int end = filename.lastIndexOf("/");
    // int end = filename.lastIndexOf("\\");
    if (end != -1) {
        uploadFilenameWithoutPath =
            filename.section("/", -1); // 获取最后一个斜杠后的所有内容
        // 如果路径使用反斜杠，可以使用以下代码
        // QString filenameWithoutPath = filename.section("\\", -1);
    }

    // 设置结构体信息
    transmitInfo.header.messageType = 1;
    // username = "xlx2";
    transmitInfo.operation = OPERATION_UPLOAD; // 设置操作为上传
    transmitInfo.result = RESULT_SUCCESS;      // 设置结果为成功
    snprintf(transmitInfo.username, sizeof(transmitInfo.username), "%s",
             username.toStdString().c_str());
    snprintf(transmitInfo.filename, sizeof(transmitInfo.filename), "%s",
             uploadFilenameWithoutPath.toStdString().c_str());

    // 8是header长度（4+4），
    // 8是opreation（4）和result（4），10（5*2）是传输时对字符串的格式化 -->
    // 先传输一个4字节的长度，然后是字符串（长度-1，1是因为'\0'），再加'\0'结束，所以每一个字符串会多出5个字节
    transmitInfo.header.messageLength = 8 + 8 + 5 * 2 +
                                        strnlen(transmitInfo.filename, 100) +
                                        strnlen(transmitInfo.username, 50);
    // qDebug() <<"transmitInfo.header.messageLength = "
    // <<transmitInfo.header.messageLength;

    // 发送结构体数据
    transmitAndSerializeMessage(transmitInfo);

    // 打开文件用于读取
    QFile file(uploadFileName);
    QFileInfo info(uploadFileName);
    qint32 filesize = info.size();
    if (!file.open(QFile::ReadOnly)) {
        return;
    }

    qDebug() << "filesize" << filesize;

    // 发送文件大小
    QDataStream out(socket);
    out << qint32(filesize); // 确保发送的是 qint64 类型

    // 准备缓冲区
    char buffer[1024];
    qint64 bytesRead;

    qint64 readdo = 0; // 已经读取的数量
    // 读取文件内容并通过 socket 发送
    // 输出开始上传信息
    // 获取当前时间并格式化为字符串
    QDateTime currentDateTime = QDateTime::currentDateTime();
    QString timeString = currentDateTime.toString("yyyy-MM-dd HH:mm:ss ");
    // 准备要输出的消息，包括时间戳
    QString message =
        "[" + timeString + "]" + uploadFilenameWithoutPath + "文件开始上传";
    ui->TEmessage->append(message);
    while (readdo < filesize) {
        bytesRead = file.read(buffer, sizeof(buffer));
        if (bytesRead <= 0) {
            break; // 如果读取的字节数小于或等于0，则跳出循环
        }
        socket->write(buffer, bytesRead); // 使用 socket 直接发送数据
        qDebug() << "bytesRead = " << bytesRead;
        readdo += bytesRead;
        int now = readdo * 100 / filesize;
        ui->progressBar->setValue(now);
    }
    // 关闭文件
    file.close();

    // 确保所有数据都被发送
    socket->flush();

    // 检查传输过程中是否有错误发生
    if (socket->state() == QAbstractSocket::ConnectedState &&
        socket->error() == QAbstractSocket::UnknownSocketError) {
        // 如果没有错误发生
        // 获取当前时间并格式化为字符串
        QDateTime currentDateTime = QDateTime::currentDateTime();
        QString timeString = currentDateTime.toString("yyyy-MM-dd HH:mm:ss ");
        QString message = "[" + timeString + "]" + uploadFilenameWithoutPath +
                          "文件上传结束，文件上传成功！";
        ui->TEmessage->append(message);
    } else {
        // 如果发生错误，输出错误信息
        qDebug()
            << "[function on_btnOk_clicked]:An error occurred during file transfer:"
            << socket->errorString();
    }
    // 断开连接
    socket->disconnectFromHost();

    // 等待连接关闭
    if (!socket->waitForDisconnected(5000)) {
        // 如果超时，则强制关闭连接
        qDebug() << "Socket did not disconnect in time, aborting.";
        socket->abort();
    } else {
        qDebug() << "Socket disconnected successfully.";
    }

    // 检查错误
    if (socket->error() != QAbstractSocket::UnknownSocketError) {
        qDebug() << "Socket error:" << socket->errorString();
    }

    on_newRe_clicked();
    return;
}

// 文件下载->接受函数
// 文件下载->接受函数
void MainWindow::onReadyRead() {
    if (flag_readyRead == 2) {
        int32_t filesize;
        QDataStream in(socket);

        if (flagi == -1) {
            socket->waitForReadyRead();
            flagi = 0;
            // in.setByteOrder(
            //     QDataStream::LittleEndian); // 设置QDataStream的字节序为小段
            // in >> filesize;
            socket->read((char *)&filesize, sizeof(int32_t));
            if (filesize == 0) {
                // 服务器打开文件错误
                return;
            }
            QFile file(downloadFileName);
            // 第一次创建文件或者清空文件内容
            if (!file.open(QIODevice::WriteOnly | QIODeviceBase::Truncate)) {
                qDebug() << "Cannot open file for writing:" << downloadFileName;
                file.close();
                return;
            }
            // qDebug() << "[on_btnDownLoad_clicked]: filesize=" << filesize;
        }

        QFile file(downloadFileName);
        // 追加数据
        if (!file.open(QIODevice::WriteOnly | QIODeviceBase::Append)) {
            qDebug() << "Cannot open file for writing:" << downloadFileName;
            file.close();
            return;
        }

        QDataStream out(&file);
        QByteArray buffer;

        int total_read = 0;

        while (socket->bytesAvailable() > 0) {
            // qDebug() <<"socket size == == "  <<socket->bytesAvailable();
            QByteArray tmp = socket->read(socket->bytesAvailable());
            buffer.append(tmp);
            total_read += tmp.length();
            // qDebug() << "[on_btnDownLoad_clicked]: buffer=" << tmp;
            if(filesize -total_read <= 0)
                break;
        }

        out.writeRawData(buffer, total_read);

        // qDebug() << "total_read = "<<total_read << "= ="<<filesize;

        // 关闭文件
        file.close();

    }
}

// 下载按钮
void MainWindow::on_btnDownLoad_clicked() {
    flagi = -1;
    flag_readyRead = 2;
    if (onCheckBoxStateChanged() == "") {
        QMessageBox::warning(this, "请选择下载文件", "未选择文件名！");
        return;
    } else {
        downloadFileName = onCheckBoxStateChanged();
    }
    // 设置结构体信息
    transmitInfo.header.messageType = 1;
    transmitInfo.operation = OPERATION_DOWNLOAD; // 设置操作为上传
    transmitInfo.result = RESULT_SUCCESS;        // 设置结果为成功
    snprintf(transmitInfo.username, sizeof(transmitInfo.username), "%s",
             username.toStdString().c_str());
    snprintf(transmitInfo.filename, sizeof(transmitInfo.filename), "%s",
             downloadFileName.toStdString().c_str());

    // 8是header长度（4+4），
    // 8是opreation（4）和result（4），10（5*2）是传输时对字符串的格式化 -->
    // 先传输一个4字节的长度，然后是字符串（长度-1，1是因为'\0'），再加'\0'结束，所以每一个字符串会多出5个字节
    transmitInfo.header.messageLength = 8 + 8 + 5 * 2 +
                                        strnlen(transmitInfo.filename, 100) +
                                        strnlen(transmitInfo.username, 50);
    // qDebug() <<"transmitInfo.header.messageLength = "
    // <<transmitInfo.header.messageLength;

    // 发送结构体数据
    transmitAndSerializeMessage(transmitInfo);

    // 用户提示（按下就显示，不代表文件真的下载完）
    QDateTime currentDateTime = QDateTime::currentDateTime();
    QString timeString = currentDateTime.toString("yyyy-MM-dd HH:mm:ss ");

    // 准备要输出的消息，包括时间戳
    QString message = timeString + downloadFileName + "下载成功";
    ui->TEmessage->append(message);

}

void MainWindow::refresh_return() {
    qDebug() << "<refresh return:>";
    connect(socket, &QTcpSocket::readyRead, [=]() {
        if (flag_readyRead == 1) {
            //  读取服务器端传来的用户文件目录
            QByteArray data;
            if (socket->bytesAvailable() > 0) {
                data = socket->readAll();
                // 处理数据
                qDebug() << "Received data:" << data;
                char *str = NULL;
                char *mybuf = NULL;
                mybuf = data.data();
                str = my_strtok(mybuf, "|");
                // qDebug() << "str_first :" << mybuf ;
                // ui->TEmyfile ->append(str);
                creatbyneed(str);
                while (1) {
                    str = my_strtok(NULL, "|");
                    if (str == NULL) {
                        break;
                    }
                    // printf("str : %s\n", str);
                    // ui->TEmyfile ->append(str);
                    creatbyneed(str);
                }
                // printf("buf: %s \n", mybuf);
                // qDebug() << "buf :" << mybuf ;
                // 获取当前时间并格式化为字符串
                QDateTime currentDateTime = QDateTime::currentDateTime();
                QString timeString = currentDateTime.toString("yyyy-MM-dd HH:mm:ss ");

                // 准备要输出的消息，包括时间戳
                // qDebug() << "check_socket called";
                QString message = timeString + "用户文件列表刷新成功";
                ui->TEmessage->append(message);
            } else {
                qDebug() << "Received data is NULL.";
            }
        }
    });
}

char *MainWindow::my_strtok_origin(char *string, const char *control,
                                   char **tmp_str) {
    unsigned char *str;
    const unsigned char *ctrl = (const unsigned char *)control;
    unsigned char map[32];
    //_ptiddata ptd = _getptd();
    /* Clear control map */
    for (int i = 0; i < 32; i++) {
        map[i] = 0;
    }
    /* Set bits in delimiter table */
    do {
        map[*ctrl >> 3] |= (1 << (*ctrl & 7));
    } while (*ctrl++);
    /* Initialize str */
    /* If string is NULL, set str to the saved
   * pointer (i.e., continue breaking tokens out of the string
   * from the last strtok call)
   */
    if (string != NULL) {
        str = (unsigned char *)string;
    } else {
        str = (unsigned char *)*tmp_str;
    }
    /* Find beginning of token (skip over leading delimiters). Note that
   * there is no token iff this loop sets str to point to the terminal
   * null (*str == '\0')
   */
    while ((map[*str >> 3] & (1 << (*str & 7))) && *str) {
        str++;
    }
    string = (char *)str;
    /* Find the end of the token. If it is not the end of the string, put a null
   * there. */
    for (; *str; str++) {
        if (map[*str >> 3] & (1 << (*str & 7))) {
            *str++ = '\0';
            break;
        }
    }
    /* Update nextoken (or the corresponding field in the per-thread data
   * structure */
    *tmp_str = (char *)str;

    if (string == (char *)str)
        return NULL;
    else
        return string;
}

char *MainWindow::my_strtok(char *string, const char *control) {
    static char *last = nullptr;
    return my_strtok_origin(string, control, &last);
}

// 分享 未完成
void MainWindow::on_btnShare_clicked() {}

// 删除（已上传的文件/夹）
void MainWindow::on_btnDelete_clicked() {
    // 检查socket状态
    if (socket->state() == QAbstractSocket::UnconnectedState) {
        // 仅当socket未连接时尝试连接到服务器
        socket->connectToHost("111.231.80.52", 8936);
    } else if (socket->state() == QAbstractSocket::ConnectedState) {
        // 如果已经连接，直接发送数据
        qDebug() << "Socket already connected. ";
    } else {
        qDebug() << "Socket is in a state not ready for connection. Current state:"
                 << socket->state();
        return; // 早期返回，不进行任何操作
    }

    qDebug() << socket->state();

    // 即将发送的指令名称（状态码） 5表示删除
    //  QByteArray order_name = "5";

    // // 在控制台输出即将发送的order_name
    // qDebug() << "Order_name:" << order_name;

    // // 发送指令
    // socket->write(order_name);

    // printf("请输入要删除的文件名:\n");
    // scanf("%s", delete_dir);

    // char* delete_dir;
    // delete_dir = (char*) malloc (sizeof(char)*100);
    // memset(delete_dir,0,sizeof(char)*100); //bzero
    // memcpy(delete_dir,"test_msg_xlx2",sizeof("test_msg_xlx2")/sizeof(char));
    // send_msg.type = MSG_TYPE_DELETE;
    // strcpy(send_msg.fname,delete_dir);

    // 更改处   需从Qt页面上读取
    QString result = onCheckBoxStateChanged();
    qDebug() << "rm sum:" << result;
    // return;
    QString deldir = result;
    // 设置结构体信息
    transmitInfo.header.messageType = 1;
    // username = "xlx2";
    // test for xlx2
    transmitInfo.operation = OPERATION_REMOVE; // 设置操作为刷新
    transmitInfo.result = RESULT_NULL;         // 设置结果为空
    snprintf(transmitInfo.username, sizeof(transmitInfo.username), "%s",
             username.toStdString().c_str());
    snprintf(transmitInfo.filename, sizeof(transmitInfo.filename), "%s",
             deldir.toStdString().c_str());

    // 8是header长度（4+4），
    // 8是opreation（4）和result（4），10（5*2）是传输时对字符串的格式化 -->
    // 先传输一个4字节的长度，然后是字符串（长度-1，1是因为'\0'），再加'\0'结束，所以每一个字符串会多出5个字节
    transmitInfo.header.messageLength = 8 + 8 + 5 * 2 +
                                        strnlen(transmitInfo.filename, 100) +
                                        strnlen(transmitInfo.username, 50);
    // qDebug() <<"transmitInfo.header.messageLength = "
    // <<transmitInfo.header.messageLength;
    qDebug() << "del_dir:" << deldir;
    // 发送结构体数据
    transmitAndSerializeMessage(transmitInfo);
    QDateTime currentDateTime = QDateTime::currentDateTime();
    QString timeString = currentDateTime.toString("yyyy-MM-dd HH:mm:ss ");

    // 准备要输出的消息，包括时间戳
    // qDebug() << "check_socket called";
    QString message = timeString + "文件删除成功";
    ui->TEmessage->append(message);

    qDebug() << "删除后刷新";

    // 测试发现刷新的依旧是之前的数据，怀疑是上一个socket没有断开，写了断开操作，果然可以，xlx真是太聪明了！
    //  断开连接
    socket->disconnectFromHost();

    // 等待连接关闭
    if (!socket->waitForDisconnected(5000)) {
        // 如果超时，则强制关闭连接
        qDebug() << "Socket did not disconnect in time, aborting.";
        socket->abort();
    } else {
        qDebug() << "Socket disconnected successfully.";
    }

    // 检查错误
    if (socket->error() != QAbstractSocket::UnknownSocketError) {
        qDebug() << "Socket error:" << socket->errorString();
    }

    on_newRe_clicked();

    // on_btnReload_clicked();

    // on_newRe_clicked();
    // on_newRe_clicked();
    // on_newRe_clicked();on_newRe_clicked();
    // test
    // on_btnDownLoad_clicked();
    // socket->write(delete_dir);
    // qDebug() << "delete_dir:" << delete_dir;
}

// 发送数据
void MainWindow::transmitAndSerializeMessage(const CommunicationInfo &info) {
    QDataStream out(socket);
    out << info.header.messageType << info.header.messageLength;
    out << info.username;
    out << static_cast<int>(info.operation);
    out << static_cast<int>(info.result);
    out << info.filename;
}

// 接受数据
void MainWindow::receivedAndDeserializeMessage(CommunicationInfo &info) {
    if (!socket || !socket->isOpen()) {
        // 套接字未打开或为null，不能进行读取操作
        return;
    }

    QDataStream in(socket);          // 创建用于读取的 QDataStream 实例
    in >> info.header.messageType;   // 读取消息类型
    in >> info.header.messageLength; // 读取消息长度
    // 读取用户名，确保缓冲区足够大并已初始化
    in.readRawData(info.username, sizeof(info.username));
    // in.readRawBytes(info.username, sizeof(info.username)); // 读取用户名
    in >> info.operation;                                 // 读取操作类型
    in >> info.result;                                    // 读取结果类型
    in.readRawData(info.filename, sizeof(info.filename)); // 读取文件名

    // 检查是否有读取错误
    if (in.status() != QDataStream::Ok) {
        // 处理错误情况，例如记录日志或抛出异常
        qDebug() << "Error reading from socket";
    }
}

void CommunicationInfoCout(CommunicationInfo &info) {
    qDebug() << "CommunicationInfo("
             << "messageType:" << static_cast<int>(info.header.messageType)
             << ", messageLength:" << info.header.messageLength
             << ", username:" << info.username
             << ", operation:" << static_cast<int>(info.operation)
             << ", result:" << static_cast<int>(info.result)
             << ", filename:" << info.filename << ")";
}

void MainWindow::CommunicationInit(CommunicationInfo &info) {
    // username = "xlx";
    info.header.messageType = 3;
    info.header.messageLength = sizeof(CommunicationInfo);
    info.operation = OPERATION_DOWNLOAD;
    info.result = RESULT_SUCCESS;
    snprintf(info.username, sizeof(info.username), "%s",
             username.toStdString().c_str());
    snprintf(info.filename, sizeof(info.filename), "%s",
             uploadFilenameWithoutPath.toStdString().c_str());
}

QString MainWindow::onCheckBoxStateChanged() {
    // 检查每个复选框的状态并汇总结果
    QString result;
    for (int i = 0; i < ui->verticalLayout_2->count(); ++i) {
        QWidget *widget = ui->verticalLayout_2->itemAt(i)->widget();
        if (widget) {
            QCheckBox *checkBox = qobject_cast<QCheckBox *>(widget);
            if (checkBox) {
                // result += '|';
                if (checkBox->isChecked())
                    result += checkBox->text();
            }
        }
    }
    qDebug() << result;
    return result;
}

void MainWindow::creatbyneed(QByteArray data) {
    // qDebug()<<"creat by need";
    // QByteArray data="xlx";

    QCheckBox *checkBox =
        new QCheckBox(data, this); // "新复选框" 是复选框旁边的文本

    // 设置复选框的其他属性，如位置和大小
    checkBox->setGeometry(10, 10, 100, 20); // x, y, width, height

    connect(checkBox, &QCheckBox::stateChanged, [](int state) {
        // 使用 qDebug() 输出测试信息
        // qDebug() << "复选框状态改变:" << (state == Qt::Checked ? "已选中" :
        // "未选中");
    });

    // 将复选框添加到主窗体或布局中
    ui->verticalLayout_2->addWidget(
        checkBox); // 假设 youLayout 是你的主窗体或父控件的布局
}

void MainWindow::on_newRe_clicked() {
    qDebug() << "<refresh>";

    // kimi 2.0
    //  遍历布局中的所有项
    // qDebug()<<"++++++";
    // qDebug()<<"sum:"<< ui->verticalLayout_2->count();
    int i = 0;
    while (i < ui->verticalLayout_2->count()) {
        //     QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
        // qDebug()<<"<be><"<<i<<">";
        QLayoutItem *item = ui->verticalLayout_2->itemAt(i);
        QCheckBox *checkBox = qobject_cast<QCheckBox *>(item->widget());
        qDebug() << "第" << i << "个已删除:" << checkBox->text();
        // 从布局中移除复选框
        checkBox->deleteLater();
        // qDebug()<<"<end><"<<i<<">";
        ++i;
    }

    // return;
    //  检查socket状态
    if (socket->state() == QAbstractSocket::UnconnectedState) {
        // 仅当socket未连接时尝试连接到服务器
        // qDebug()<<"当socket未连接时尝试连接到服务器";
        socket->connectToHost("111.231.80.52", 8936);
    } else if (socket->state() == QAbstractSocket::ConnectedState) {
        // 如果已经连接，直接发送数据
        qDebug() << "Socket already connected. ";
    } else {
        qDebug() << "Socket is in a state not ready for connection. Current state:"
                 << socket->state();
        return; // 早期返回，不进行任何操作
    }

    qDebug() << socket->state();
    // 即将发送的指令名称（状态码） 4表示刷新
    // QByteArray order_name = "4";

    // 设置结构体信息
    transmitInfo.header.messageType = 1;
    // 写入结构体 ok
    //  username = "xlx2";
    transmitInfo.operation = OPERATION_REFRESH; // 设置操作为刷新
    transmitInfo.result = RESULT_NULL;          // 设置结果为空
    snprintf(transmitInfo.username, sizeof(transmitInfo.username), "%s",
             username.toStdString().c_str());
    snprintf(transmitInfo.filename, sizeof(transmitInfo.filename), "%s",
             uploadFilenameWithoutPath.toStdString().c_str());

    // 8是header长度（4+4），
    // 8是opreation（4）和result（4），10（5*2）是传输时对字符串的格式化 -->
    // 先传输一个4字节的长度，然后是字符串（长度-1，1是因为'\0'），再加'\0'结束，所以每一个字符串会多出5个字节
    transmitInfo.header.messageLength = 8 + 8 + 5 * 2 +
                                        strnlen(transmitInfo.filename, 100) +
                                        strnlen(transmitInfo.username, 50);
    // qDebug() <<"transmitInfo.header.messageLength = "
    // <<transmitInfo.header.messageLength;

    // 发送结构体数据
    transmitAndSerializeMessage(transmitInfo);

    flag_readyRead = 1;
    refresh_return();
}
